package com.fangda.network.util;

import lombok.extern.java.Log;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Locale;
import java.util.logging.Level;

/**
 * 字符转化工具
 * @author 赵方方
 */
@Log
public class ByteUtil {

	/**
	 * 字节数组转字符串
	 *
	 * @param array
	 *            字节数组
	 * @param start
	 *            起始位置
	 * @param len
	 *            长度
	 * @return 字符串
	 */
	public static String byteArrayToHexString(byte[] array, int start, int len) {
		if (start > array.length || (start + len) > array.length) {
			log.log(Level.INFO, "数组越界");
			return "";
		}
		StringBuilder hexString = new StringBuilder();
		for (int i = start; i < start + len; i++) {
			int intVal = array[i] & 0xff;
			if (intVal < 0x10) {
				hexString.append("0");
			}
			hexString.append(Integer.toHexString(intVal));
		}
		return hexString.toString().toUpperCase();
	}

	public static String byteArrayToHexString(byte[] array) {
		return byteArrayToHexString(array, 0, array.length);
	}

	/**
	 * bytes字符串转换为Byte值
	 *
	 * @param src
	 *            String Byte字符串，每个Byte之间没有分隔符(字符范围:0-9 A-F)
	 * @return byte[]
	 */
	public static byte[] hexString2Bytes(String src) {
		/* 对输入值进行规范化整理 */
		src = src.trim().replace(" ", "").toUpperCase(Locale.US);
		// 处理值初始化
		int m = 0, n = 0;
		int iLen = src.length() / 2; // 计算长度
		byte[] ret = new byte[iLen]; // 分配存储空间

		for (int i = 0; i < iLen; i++) {
			m = i * 2 + 1;
			n = m + 1;
			ret[i] = (byte) (Integer.decode("0x" + src.substring(i * 2, m) + src.substring(m, n)) & 0xFF);
		}
		return ret;
	}

	/**
	 * 字节流转
	 *
	 * @param in 输入流
	 * @return 字符串
	 */
	public static String inputStream2HexString(InputStream in) {
		StringBuffer info = new StringBuffer();
		BufferedInputStream buf = new BufferedInputStream(in);
		byte[] buffer = new byte[1024];
		int iRead;
		try {
			while ((iRead = buf.read(buffer)) != -1) {
				info.append(byteArrayToHexString(buffer).subSequence(0, iRead * 2));
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return info.toString();
	}

	public static int getInt(byte[] bytes) {
		return 0xFF & bytes[0] | 0xFF & bytes[1] << 8 | 0xFF & bytes[2] << 16 | 0xFF & bytes[3] << 24;
	}

	/**
	 * Short转byte[] 小端
	 * @param src
	 * @return
	 */
	public static byte[] formatShortL(short src) {
		return formatShort(src, false);
	}

	/**
	 * Int转byte[] 大端
	 * @param src
	 * @return
	 */
	public static byte[] formatShortB(short src) {
		return formatShort(src, true);
	}

	private static byte[] formatShort(short src, boolean isBig) {
		ByteBuffer buffer = ByteBuffer.allocate(2);
		if(isBig) {
			buffer.order(ByteOrder.BIG_ENDIAN);
		} else {
			buffer.order(ByteOrder.LITTLE_ENDIAN);
		}
		buffer.asShortBuffer().put(src);
		return buffer.array();
	}

	/**
	 * bytes转 short 小端
	 * @param bytes
	 * @param start
	 * @param length
	 * @return
	 */
	public static short parseShortL(byte[] bytes, int start, int length) {
		ByteBuffer buffer = ByteBuffer.wrap(bytes, start, length);
		buffer.order(ByteOrder.LITTLE_ENDIAN);
		short id = buffer.getShort();
		return id;
	}

	public static short parseShortL(String src, int start, int length) {
		byte[] bytes = ByteUtil.hexString2Bytes(src);
		short id = ByteUtil.parseShortL(bytes, start, length);
		return id;
	}

	public static short parseShortL(String src) {
		byte[] bytes = ByteUtil.hexString2Bytes(src);
		short id = ByteUtil.parseShortL(bytes, 0, bytes.length);
		return id;
	}

	/**
	 * bytes转 short 大端
	 * @param bytes
	 * @param start
	 * @param length
	 * @return
	 */
	public static short parseShortB(byte[] bytes, int start, int length) {
		ByteBuffer buffer = ByteBuffer.wrap(bytes, start, length);
		buffer.order(ByteOrder.BIG_ENDIAN);
		short id = buffer.getShort();
		return id;
	}

	public static short parseShort(byte[] bytes, int start, int length, ByteOrder order) {
		ByteBuffer buffer = ByteBuffer.wrap(bytes, start, length);
		buffer.order(order);
		short id = buffer.getShort();
		return id;
	}

	/**
	 * Int转byte[] 小端
	 * @param src
	 * @return
	 */
	public static byte[] formatIntL(int src) {
		return formatInt(src, false);
	}

	/**
	 * Int转byte[] 大端
	 * @param src
	 * @return
	 */
	public static byte[] formatIntB(int src) {
		return formatInt(src, true);
	}

	private static byte[] formatInt(int src, boolean isBig) {
		ByteBuffer buffer = ByteBuffer.allocate(4);
		if(isBig) {
			buffer.order(ByteOrder.BIG_ENDIAN);
		} else {
			buffer.order(ByteOrder.LITTLE_ENDIAN);
		}
		buffer.asIntBuffer().put(src);
		return buffer.array();
	}

	/**
	 * 一个字节转化成Int 类型，一般都是长度
	 * @param bytes
	 * @param start
	 * @return
	 */
	public static Integer parseByteToInt(byte[] bytes, int start, int length) {
		String str = byteArrayToHexString(bytes, start, length);
		Integer i = Integer.parseInt(str, 16);
		return i;
	}

	public static Byte parseByte(byte[] bytes, int start) {
		Byte b = bytes[start];
		return b;
	}

	/**
	 * bytes转 int 小端
	 * @param bytes
	 * @param start
	 * @param length
	 * @return
	 */
	public static int parseIntL(byte[] bytes, int start, int length) {
		ByteBuffer buffer = ByteBuffer.wrap(bytes, start, length);
		buffer.order(ByteOrder.LITTLE_ENDIAN);
		int id = buffer.getInt();
		return id;
	}

	/**
	 * byte转int 大端
	 * @param bytes
	 * @param start
	 * @param length
	 * @return
	 */
	public static int parseIntB(byte[] bytes, int start, int length) {
		ByteBuffer buffer = ByteBuffer.wrap(bytes, start, length);
		buffer.order(ByteOrder.BIG_ENDIAN);
		int id = buffer.getInt();
		return id;
	}

	/**
	 * byte转int 大端
	 * @param bytes
	 * @param start
	 * @param length
	 * @return
	 */
	public static int parseInt(byte[] bytes, int start, int length, ByteOrder order) {
		ByteBuffer buffer = ByteBuffer.wrap(bytes, start, length);
		buffer.order(order);
		int id = buffer.getInt();
		return id;
	}

	/**
	 * byte[]转long小端
	 * @param bytes
	 * @param start
	 * @param length
	 * @return
	 */
	public static long parseLongL(byte[] bytes, int start, int length) {
		ByteBuffer buffer = ByteBuffer.wrap(bytes, start, length);
		buffer.order(ByteOrder.LITTLE_ENDIAN);
		long id = buffer.getLong();
		return id;
	}

	/**
	 * byte[]转long大端
	 * @param bytes
	 * @param start
	 * @param length
	 * @return
	 */
	public static long parseLongB(byte[] bytes, int start, int length) {
		ByteBuffer buffer = ByteBuffer.wrap(bytes, start, length);
		buffer.order(ByteOrder.BIG_ENDIAN);
		long id = buffer.getLong();
		return id;
	}

	public static long parseLong(byte[] bytes, int start, int length, ByteOrder order) {
		ByteBuffer buffer = ByteBuffer.wrap(bytes, start, length);
		buffer.order(order);
		long id = buffer.getLong();
		return id;
	}

	public static float parseFloat(byte[] bytes, int start, int length, ByteOrder order) {
		ByteBuffer buffer = ByteBuffer.wrap(bytes, start, length);
		buffer.order(order);
		float id = buffer.getFloat();
		return id;
	}

	public static float parseFloatB(byte[] bytes, int start, int length) {
		ByteBuffer buffer = ByteBuffer.wrap(bytes, start, length);
		buffer.order(ByteOrder.BIG_ENDIAN);
		float id = buffer.getFloat();
		return id;
	}

	public static float parseFloatL(byte[] bytes, int start, int length) {
		ByteBuffer buffer = ByteBuffer.wrap(bytes, start, length);
		buffer.order(ByteOrder.LITTLE_ENDIAN);
		float id = buffer.getFloat();
		return id;
	}

	public static double parseDouble(byte[] bytes, int start, int length, ByteOrder order) {
		ByteBuffer buffer = ByteBuffer.wrap(bytes, start, length);
		buffer.order(order);
		double id = buffer.getDouble();
		return id;
	}

	public static double parseDoubleB(byte[] bytes, int start, int length) {
		ByteBuffer buffer = ByteBuffer.wrap(bytes, start, length);
		buffer.order(ByteOrder.BIG_ENDIAN);
		double id = buffer.getDouble();
		return id;
	}

	public static double parseDoubleL(byte[] bytes, int start, int length) {
		ByteBuffer buffer = ByteBuffer.wrap(bytes, start, length);
		buffer.order(ByteOrder.LITTLE_ENDIAN);
		double id = buffer.getDouble();
		return id;
	}

	/**
	 * Long转byte[] 小端
	 * @param src
	 * @return
	 */
	public static byte[] formatLongL(long src) {
		return formatLong(src, false);
	}

	/**
	 * Long转byte[] 大端
	 * @param src
	 * @return
	 */
	public static byte[] formatLongB(long src) {
		return formatLong(src, true);
	}

	private static byte[] formatLong(long src, boolean isBig) {
		ByteBuffer buffer = ByteBuffer.allocate(8);
		if(isBig) {
			buffer.order(ByteOrder.BIG_ENDIAN);
		} else {
			buffer.order(ByteOrder.LITTLE_ENDIAN);
		}
		buffer.asLongBuffer().put(src);

		return buffer.array();
	}
}
